import React, { Component } from 'react';
import { Button, Card, Form, Input, message, Progress, Space, Spin, Upload } from 'antd';
import { FormInstance } from 'antd/lib/form';
import { Store, ValidateErrorEntity } from 'rc-field-form/lib/interface'
import { devRes, getRes, prodRes } from '../../configFile';
import ManuForDeviceSelect from './ManuForDeviceSelect';
import { searchManufacturer } from '../../requests/Manufacturer';
import DataCategory from '../../types/DataCategory';
import {
    addDeviceAttachment,
    addDevicePicture,
    addDeviceStereoPicture,
    checkDeviceAttachment,
    checkDevicePicture,
    checkDeviceStereoPicture,
    deviceAdminAddDevice,
    supervisorAddDevice,
    uploadTwoDimensionalData
} from '../../requests/Device';
import DeviceData from '../../types/DeviceData'
import DeviceAdminForDevice from './DeviceAdminForDevice';
import { searchUser } from '../../requests/supervisor';
import DataCategoryForDevice from './DataCategoryForDevice';
import DataType from '../../types/DataType';
import SELECTtoFill from './SELECTtoFill';
import FiletoFill from './FiletoFill';
import Axios from 'axios';
import { UploadOutlined } from '@ant-design/icons';
import { UploadFile } from 'antd/lib/upload/interface';
import { RootState } from '../../reducers';
import { connect, ConnectedProps } from 'react-redux';
import UserType from '../../types/UserType';

interface IProps extends ConnectedProps<typeof connector> {
}

interface IState {
    attachProgress: number
    stereoProgress: number      //3d图片上传进度
    manufacturerID: number
    isLoading: boolean
    addedDataCategory: DataCategory[]
    textDeviceData: DeviceData[]
    selectDeviceData: DeviceData[]
    twoDimensionalDeviceData: DeviceData[]
    deviceAdminID?: number
    twoDFile: { file: File, cateID: number }[]
    attachFileList: UploadFile<any>[]
    pictureFileList: UploadFile<any>[]
    stereoPictureFileList: UploadFile<any>[]

}

class AddDevice extends Component<IProps, IState> {
    formRef = React.createRef<FormInstance>()

    constructor(props: IProps) {
        super(props)
        this.state = {
            attachProgress: 0,
            stereoProgress: 0,
            pictureFileList: [],
            attachFileList: [],
            addedDataCategory: [],
            manufacturerID: -1,
            isLoading: false,
            textDeviceData: [],
            selectDeviceData: [],
            twoDimensionalDeviceData: [],
            twoDFile: [],
            stereoPictureFileList: []
        }
    }

    layout = {
        labelCol: { span: 4 },
        wrapperCol: { span: 16 },
    };
    tailLayout = {
        wrapperCol: { offset: 4 },
    };

    //上传二维数据
    uploadTwoDFunc = async (deviceID: number) => {
        const allCateID = this.state.addedDataCategory.map(item => item.dataCategoryID)
        const neededTwoD = this.state.twoDFile.filter(item => allCateID.indexOf(item.cateID) !== -1)    //已添加数据类型里有的所有二维数据类型
        const res: Array<devRes | prodRes> = await Axios.all(neededTwoD.map(item => uploadTwoDimensionalData(item.file, deviceID, item.cateID)))
        let flag: boolean = true;
        res.forEach(item => {
            if (!getRes(item).isSuccessful) {
                flag = false;
            }
        })
        return flag;
    }

    //设置3d图片上传进度条
    setAttachProgress = (progress: any) => {
        this.setState({
            attachProgress: (progress.loaded / progress.total) * 100
        }, () => { console.log("进度", this.state.attachProgress); }
        )
    }

    //设置3d图片上传进度条
    setUploadProgress = (progress: any) => {
        this.setState({
            stereoProgress: (progress.loaded / progress.total) * 100
        }, () => { console.log("进度", this.state.stereoProgress); }
        )
    }


    //输入合法函数
    onFinish: (values: Store) => void = async values => {

        this.state.addedDataCategory.forEach(item => {
            if (item.dataType === DataType.TEXT) {
                //除去重复
                this.setState({
                    textDeviceData: this.state.textDeviceData.filter(itemAdded => itemAdded.categoryID !== item.dataCategoryID)
                })
                //加入新值
                this.state.textDeviceData.push({
                    dataValue: values[item.dataCategoryID],
                    categoryID: item.dataCategoryID
                })
                this.setState({ ...this.state });
            }
            if (item.dataType === DataType.SELECT) {
                //除去重复
                this.setState({
                    selectDeviceData: this.state.selectDeviceData.filter(itemAdded => itemAdded.categoryID !== item.dataCategoryID)
                })
                //加入新值
                this.state.selectDeviceData.push({
                    dataValue: values[item.dataCategoryID],
                    categoryID: item.dataCategoryID
                })
                this.setState({ ...this.state });
            }
        })
        this.setState({ ...this.state });
        const { textDeviceData, selectDeviceData, deviceAdminID, stereoPictureFileList } = this.state
        try {
            //加载中
            this.setState({ isLoading: true })
            //添加设备
            const res = this.props.userType === UserType.SUPERVISOR ?
                getRes(await supervisorAddDevice(values.deviceName, textDeviceData.concat(selectDeviceData), values.manu.key, deviceAdminID))
                :
                getRes(await deviceAdminAddDevice(values.deviceName, textDeviceData.concat(selectDeviceData), values.manu.key));
            if (res.isSuccessful === false) {
                message.error("设备添加失败")
                return; //不清空
            } else {
                message.success("设备添加成功")
            }

            //添加确认后发送二维数据
            //从添加设备（非二维数据）返回数据中拿设备ID
            const deviceID = res.data;
            //并发发送二维数据
            if (!await this.uploadTwoDFunc(deviceID)) {
                message.error("二维数据添加失败，请在编辑设备页面重新添加")
            }

            //发送附件
            const { attachFileList, pictureFileList } = this.state
            //上传附件检测
            if (attachFileList.length > 0) {
                const fileNames = attachFileList.map(item => item.name)
                const fileSizes = attachFileList.map(item => item.size)
                const attachCheck = getRes(await checkDeviceAttachment(deviceID, fileNames, fileSizes))
                if (attachCheck.isSuccessful === true) {
                    message.success("附件允许上传")
                    //上传附件                  TODO:类型as unknown，从UploadFile<any>转换到File
                    const fileList: File[] = attachFileList as unknown as File[];
                    const addAttach = getRes(await addDeviceAttachment(deviceID, fileList, this.setAttachProgress))
                    if (addAttach.isSuccessful === true) {
                        message.success("附件上传成功")
                    } else {
                        message.error("附件上传失败，请在编辑设备页面重新添加" + addAttach.message)
                    }
                } else {
                    message.error("附件上传检测失败，请在编辑设备页面重新添加" + attachCheck.message)
                }
            }
            //发送图片
            //上传图片检测
            if (pictureFileList.length > 0) {
                const pictureCheck = getRes(await checkDevicePicture(deviceID));
                if (pictureCheck.isSuccessful === true) {
                    message.success("图片允许上传")
                    //上传图片                  TODO:类型as unknown
                    const fileList: File[] = pictureFileList as unknown as File[];
                    const addPicture = getRes(await addDevicePicture(deviceID, fileList))
                    if (addPicture.isSuccessful === true) {
                        message.success("图片上传成功")
                    } else {
                        message.error("图片上传失败，请在编辑设备页面重新添加" + addPicture.message)
                    }
                } else {
                    message.error("图片上传检测失败，请在编辑设备页面重新添加" + pictureCheck.message)
                }
            }

            if (stereoPictureFileList.length > 0) {
                //发送3D图片
                const fileNames = stereoPictureFileList.map(item => item.name)
                const fileSizes = stereoPictureFileList.map(item => item.size)
                const stereoPictureCheck = getRes(await checkDeviceStereoPicture(deviceID, fileNames, fileSizes));
                if (stereoPictureCheck.isSuccessful === true) {
                    message.success("3D图片允许上传")
                    //上传图片                  TODO:类型as unknown
                    const fileList: File[] = stereoPictureFileList as unknown as File[];
                    const addStereoPicture = getRes(await addDeviceStereoPicture(deviceID, fileList, this.setUploadProgress))
                    if (addStereoPicture.isSuccessful === true) {
                        message.success("3D图片上传成功")
                    } else {
                        message.error("3D图片上传失败" + addStereoPicture.message)
                    }
                } else {
                    message.error("3D图片上传检测失败，请在编辑设备页面重新添加" + stereoPictureCheck.message)
                }
            }

            //最后上传成功后，清空
            this.formRef.current?.resetFields();
            this.setState({
                attachProgress: 0,
                stereoProgress: 0,
                addedDataCategory: [],
                stereoPictureFileList: [],
                pictureFileList: [],
                attachFileList: []
            })

        } catch (err) {
            message.error(err.toString())
        } finally {
            this.setState({ isLoading: false })
        }

    }


    onFinishFailed = (errorInfo: ValidateErrorEntity) => {
        message.error(errorInfo.errorFields[0].errors[0]);
    };

    //模态框选中数据类型回调函数
    setSelectedCate = (arr: Array<DataCategory>) => {
        this.setState({
            addedDataCategory: arr
        })
    }

    //删除已选中的数据类型
    deleteAddedCate = (cateID: number) => {
        this.setState({
            addedDataCategory: this.state.addedDataCategory.filter(item => item.dataCategoryID !== cateID)
        })
    }

    //二维数据获得文件
    getFile = (file: File, cateID: number) => {
        this.setState({ twoDFile: this.state.twoDFile.filter(item => item.cateID !== cateID) });      //覆盖之前上传
        this.state.twoDFile.push({ file, cateID });
        this.setState({ ...this.state });
    }

    //移除附件
    attachRemove = (file: UploadFile<any>) => {
        //处理列表
        this.setState(state => {
            const index = state.attachFileList.indexOf(file);
            const newFileList = state.attachFileList.slice();
            newFileList.splice(index, 1);
            return {
                attachFileList: newFileList,
            };
        });
    }
    //移除图片
    pictureRemove = (file: UploadFile<any>) => {
        //处理列表
        this.setState(state => {
            const index = state.pictureFileList.indexOf(file);
            const newFileList = state.pictureFileList.slice();
            newFileList.splice(index, 1);
            return {
                pictureFileList: newFileList,
            };
        });
    }

    //移除3D图片
    stereoPictureRemove = (file: UploadFile<any>) => {
        //处理列表
        this.setState(state => {
            const index = state.stereoPictureFileList.indexOf(file);
            const newFileList = state.stereoPictureFileList.slice();
            newFileList.splice(index, 1);
            return {
                stereoPictureFileList: newFileList,
            };
        });
    }

    //附件上传前加入文件列表
    beforeAttachUpload = (file: UploadFile<any>) => {
        if (this.state.attachFileList.map(item => item.name).includes(file.name)) {
            message.error("已加入同名文件 " + file.name);
            return false;
        }
        this.setState(state => ({
            attachFileList: [...state.attachFileList, file],
        }));
        return false;
    }
    //图片上传前加入文件列表
    beforePictureUpload = (file: UploadFile<any>) => {
        if (this.state.pictureFileList.map(item => item.name).includes(file.name)) {
            message.error("已加入同名文件 " + file.name);
            return false;
        }
        this.state.pictureFileList.push(file);
        this.setState({ ...this.state });
        return false;
    }

    //3D图片上传前加入文件列表
    beforeStereoPictureUpload = (file: UploadFile<any>) => {
        if (this.state.stereoPictureFileList.map(item => item.name).includes(file.name)) {
            message.error("已加入同名文件 " + file.name);
            return false;
        }
        this.state.stereoPictureFileList.push(file);
        this.setState({ ...this.state });
        return false;
    }

    render() {
        const { addedDataCategory } = this.state
        return (
            <div>
                <Spin size='large' spinning={this.state.isLoading}>
                    <Card title="添加设备">

                        <Form
                            onFinishFailed={this.onFinishFailed}
                            onFinish={this.onFinish}
                            ref={this.formRef}
                            {...this.layout}
                            name="addDevice"
                        >

                            <Form.Item
                                label="设备名称"
                                name="deviceName"
                                rules={[
                                    {
                                        required: true,
                                        message: '设备名称必填',
                                    },
                                ]}
                            >
                                <Input />
                            </Form.Item>

                            {
                                this.props.userType === UserType.SUPERVISOR ?

                                    <Form.Item
                                        label="指定管理员（可选）"
                                        name="deviceAdmin"
                                        rules={[{ required: false }]}
                                    >
                                        <DeviceAdminForDevice queryFunc={searchUser} />
                                    </Form.Item>
                                    :
                                    ''
                            }

                            <Form.Item
                                label="厂商名称"
                                name="manu"
                                rules={[{ required: true, message: "厂商必填" }]}
                            >
                                <ManuForDeviceSelect queryFunc={searchManufacturer} />
                            </Form.Item>


                            <Form.Item label="上传附件">
                                <Upload
                                    multiple={true}
                                    onRemove={this.attachRemove}
                                    beforeUpload={this.beforeAttachUpload}
                                    fileList={this.state.attachFileList}
                                >
                                    <Button icon={<UploadOutlined />}>选择附件</Button>
                                </Upload>
                                <Progress percent={this.state.attachProgress} style={this.state.attachProgress === 0 ? { display: 'none' } : {}} />
                            </Form.Item>

                            <Form.Item label="上传图片">
                                <Upload
                                    multiple={true}
                                    onRemove={this.pictureRemove}
                                    beforeUpload={this.beforePictureUpload}
                                    fileList={this.state.pictureFileList}
                                    accept="image/*"
                                >
                                    <Button icon={<UploadOutlined />}>选择图片</Button>
                                </Upload>
                            </Form.Item>

                            <Form.Item
                                label="上传3D图片"
                                extra="请上传多张图片或其压缩包，以一定角度递增拍摄并命名，如&quot;1.jpg&quot;、&quot;2.jpg&quot;等"
                            >
                                <Upload
                                    multiple={true}
                                    onRemove={this.stereoPictureRemove}
                                    beforeUpload={this.beforeStereoPictureUpload}
                                    fileList={this.state.stereoPictureFileList}
                                    accept='image/*,
                                     application/x-gzip,
                                     application/x-bzip2,
                                     application/zip,
                                     application/x-rar,
                                     application/x-tar,
                                     application/x-7z-compressed'
                                >
                                    <Button icon={<UploadOutlined />}>选择图片</Button>
                                </Upload>
                                <Progress percent={Math.floor(this.state.stereoProgress)} style={this.state.attachProgress === 0 ? { display: 'none' } : {}} />
                            </Form.Item>

                            <Card title="设备参数" bordered={false}
                                extra={<DataCategoryForDevice key={this.state.addedDataCategory.length}
                                    propCate={this.state.addedDataCategory}
                                    setSelectedCate={this.setSelectedCate} />}>
                                {
                                    addedDataCategory.map(item => {
                                        return (
                                            <Form.Item
                                                labelCol={{ span: 4 }}
                                                label={item.dataCategoryName}
                                                name={item.dataCategoryID}
                                                key={item.dataCategoryID}
                                                rules={[{ required: true, message: "参数内容必填" }]}
                                            >
                                                {
                                                    item.dataType === DataType.TEXT ?
                                                        (<Space>
                                                            <Input style={{ width: 400 }} placeholder="参数内容" />
                                                            <Button danger
                                                                onClick={this.deleteAddedCate.bind(this, item.dataCategoryID)}
                                                            >
                                                                删除
                                                            </Button>
                                                        </Space>)
                                                        :
                                                        item.dataType === DataType.SELECT ?
                                                            (<SELECTtoFill propCate={item}
                                                                deleteAddedCate={this.deleteAddedCate} />)
                                                            :
                                                            (<Space>
                                                                <FiletoFill getFile={this.getFile}
                                                                    cateID={item.dataCategoryID} />
                                                                <Button danger
                                                                    onClick={this.deleteAddedCate.bind(this, item.dataCategoryID)}>删除</Button>
                                                            </Space>)
                                                }
                                            </Form.Item>
                                        )
                                    })
                                }
                            </Card>

                            <Form.Item {...this.tailLayout}>
                                <Button type="primary" htmlType="submit" size="large">
                                    确认添加
                                </Button>
                            </Form.Item>
                        </Form>
                    </Card>
                </Spin>
            </div>
        )
    }
}

//connect加入props
const mapStateToProps = (state: RootState) => {
    return {
        userID: state.loginReducers.userID,
        userType: state.loginReducers.userType
    }
}
const connector = connect(mapStateToProps);

export default connector(AddDevice);